// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf

#include "MgcLightState.h"

MgcImplementRTTI(MgcLightState,MgcRenderState);
MgcImplementStream(MgcLightState);
MgcImplementDefaultState(MgcLightState);

//----------------------------------------------------------------------------
MgcRenderState::Type MgcLightState::GetType () const
{
    return RS_LIGHT;
}
//----------------------------------------------------------------------------
MgcLightState::MgcLightState ()
{
}
//----------------------------------------------------------------------------
MgcLightState::~MgcLightState ()
{
    DetachAll();
}
//----------------------------------------------------------------------------
void MgcLightState::Update (MgcRenderState*& rpkOldState)
{
    // Lights get accumulated, not replaced.  The default light state is used
    // for the accumulation.

    assert( rpkOldState == ms_spkDefault );
    if ( rpkOldState != ms_spkDefault )
        return;

    for (unsigned int uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
    {
        if ( m_aspkLight[uiIndex] )
        {
            // Default light state accumulates the lights during the
            // recursive traversal.  A check is made here to see if more than
            // the maximum number of lights has occurred in the current path
            // of traversal.
            unsigned int uiPos = ms_spkDefault->Attach(m_aspkLight[uiIndex]);
            assert( uiPos < MAX_LIGHTS );
        }
    }
}
//----------------------------------------------------------------------------
void MgcLightState::Restore (MgcRenderState* pkOldState)
{
    // This light state might have added lights to the default light state
    // during the accumulation phase.  They need to be removed.

    assert( pkOldState == ms_spkDefault );
    if ( pkOldState != ms_spkDefault )
        return;

    for (unsigned int uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
    {
        if ( m_aspkLight[uiIndex] )
        {
            // A check is made here to make sure no one else has removed the
            // light.  This assertion should not fail given the implementation
            // of MgcLightState::Attach.
            unsigned int uiPos = ms_spkDefault->Detach(m_aspkLight[uiIndex]);
            assert( uiPos < MAX_LIGHTS );
        }
    }
}
//----------------------------------------------------------------------------
MgcRenderState* MgcLightState::Copy ()
{
    MgcLightState* pkState = new MgcLightState;
    for (unsigned int uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
        pkState->m_aspkLight[uiIndex] = m_aspkLight[uiIndex];

    return pkState;
}
//----------------------------------------------------------------------------
unsigned int MgcLightState::Attach (MgcLight* pkLight)
{
    assert( pkLight );
    if ( !pkLight )
        return MAX_LIGHTS;

    unsigned int uiIndex;

    // A light should not be attached twice.
    for (uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
    {
        if ( m_aspkLight[uiIndex]
        &&   m_aspkLight[uiIndex]->GetID() == pkLight->GetID() )
        {
            assert( false );
            return MAX_LIGHTS;
        }
    }

    for (uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
    {
        if ( m_aspkLight[uiIndex] == 0 )
        {
            m_aspkLight[uiIndex] = pkLight;
            return uiIndex;
        }
    }

    return MAX_LIGHTS;
}
//----------------------------------------------------------------------------
unsigned int MgcLightState::Detach (MgcLight* pkLight)
{
    assert( pkLight );
    if ( !pkLight )
        return MAX_LIGHTS;

    for (unsigned int uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
    {
        if ( m_aspkLight[uiIndex]
        &&   m_aspkLight[uiIndex]->GetID() == pkLight->GetID() )
        {
            m_aspkLight[uiIndex] = 0;
            return uiIndex;
        }
    }

    return MAX_LIGHTS;
}
//----------------------------------------------------------------------------
MgcLightPtr MgcLightState::Detach (unsigned int uiIndex)
{
    assert( uiIndex < MAX_LIGHTS );
    if ( uiIndex >= MAX_LIGHTS )
        return 0;

    MgcLightPtr spSave = m_aspkLight[uiIndex];
    m_aspkLight[uiIndex] = 0;
    return spSave;
}
//----------------------------------------------------------------------------
void MgcLightState::DetachAll ()
{
    for (unsigned int uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
        m_aspkLight[uiIndex] = 0;
}
//----------------------------------------------------------------------------
unsigned int MgcLightState::GetQuantity () const
{
    unsigned int uiQuantity = 0;

    for (unsigned int uiIndex = 0; uiIndex < MAX_LIGHTS; uiIndex++)
    {
        if ( m_aspkLight[uiIndex] )
            uiQuantity++;
    }

    return uiQuantity;
}
//----------------------------------------------------------------------------
MgcLight* MgcLightState::Get (unsigned int uiIndex)
{
    assert( uiIndex < MAX_LIGHTS );
    if ( uiIndex >= MAX_LIGHTS )
        return 0;

    return m_aspkLight[uiIndex];
}
//----------------------------------------------------------------------------

//---------------------------------------------------------------------------
// streaming
//---------------------------------------------------------------------------
MgcObject* MgcLightState::Factory (MgcStream& rkStream)
{
    MgcLightState* pkObject = new MgcLightState;
    MgcStream::Link* pkLink = new MgcStream::Link(pkObject);
    pkObject->Load(rkStream,pkLink);
    return pkObject;
}
//---------------------------------------------------------------------------
void MgcLightState::Load (MgcStream& rkStream, MgcStream::Link* pkLink)
{
    MgcRenderState::Load(rkStream,pkLink);

    // link data
    for (unsigned int uiI = 0; uiI < MAX_LIGHTS; uiI++)
    {
        MgcLight* pkLight;
        MgcStreamRead(rkStream,pkLight);
        pkLink->Add(pkLight);
    }
}
//---------------------------------------------------------------------------
void MgcLightState::Link (MgcStream& rkStream, MgcStream::Link* pkLink)
{
    MgcRenderState::Link(rkStream,pkLink);

    for (unsigned int uiI = 0; uiI < MAX_LIGHTS; uiI++)
    {
        MgcObject* pkLinkID = pkLink->GetLinkID();
        m_aspkLight[uiI] = (MgcLight*)rkStream.GetFromMap(pkLinkID);
    }
}
//---------------------------------------------------------------------------
bool MgcLightState::Register (MgcStream& rkStream)
{
    if ( !MgcRenderState::Register(rkStream) )
        return false;

    for (unsigned int uiI = 0; uiI < MAX_LIGHTS; uiI++)
    {
        if ( m_aspkLight[uiI] )
            m_aspkLight[uiI]->Register(rkStream);
    }

    return true;
}
//---------------------------------------------------------------------------
void MgcLightState::Save (MgcStream& rkStream)
{
    MgcRenderState::Save(rkStream);

    // link data
    for (unsigned int uiI = 0; uiI < MAX_LIGHTS; uiI++)
        MgcStreamWrite(rkStream,m_aspkLight[uiI]);
}
//---------------------------------------------------------------------------
